<?php
/**
 * Created by PhpStorm.
 * User: 85210755@qq.com
 * NickName: 柏宇娜
 * Date: 2018/7/4 17:06
 */

namespace app;

use think\Cache;
use think\Db;

class Im
{
    protected $ws;
    protected $log;
    protected $save_time;

    public function __construct($swoole, $log, $save_time)
    {
        $this->ws        = $swoole;
        $this->log       = $log;
        $this->save_time = $save_time;
    }

    public function handle($frame)
    {
        $data = $frame->data;
        if (!isset($data['type']) || !in_array($data['type'], ['send_msg', 'get_msg', 'read'])) {
            $this->ws->push($frame->fd, json('请求参数错误', 'error'));
        }
        $this->{$data['type']}($frame);
    }

    public function send_msg($frame)
    {
        $data = $frame->data;
        if (!trim($data['msg'])) {
            $this->ws->push($frame->fd, json('消息内容不能为空!', 'error'));
            return;
        }

        if ($data['from'] == $data['to']) {
            $this->ws->push($frame->fd, json('不能给自己发信息哦!', 'error'));
            return;
        }

        $field   = ['user' => 'user_id', 'seller' => 'id', 'admin_user' => 'id'];
        $uid     = explode('-', $data['to']);
        $to_user = Db::name($uid[0])->where($field[$uid[0]], $uid[1])->count();
        if (!$to_user) {
            throw new \Exception('用户不存在');
        }
        $row       = [
            '__from'          => $data['from'],
            '__to'            => $data['to'],
            'msg'             => $data['msg'],
            'is_contain_file' => $data['is_contain_file'] ?? 0,//0文本消息，1包含图片
            'is_read'         => 0,
            'add_time'        => time()
        ];
        $row['id'] = Db::name('im_msg')->insertGetId($row);
        $task      = [
            'type' => 'im_push',
            'data' => $row,
            'fds'  => [$frame->fd],
        ];

        $to_fd = Cache::tag('login')->get($data['to']);
        if ($to_fd) {
            $task['fds'][] = $to_fd;
        }

        $this->ws->task($task);
    }

    public function get_msg($frame)
    {
        $list = Db::name('im_msg')
            ->whereRaw("(`__from`='{$frame->data['to']}' AND `__to`='{$frame->data['from']}') OR (`__to`='{$frame->data['to']}' AND `__from`='{$frame->data['from']}')")
            ->order('id DESC')->select();
        if ($list) {
            Db::name('im_msg')->whereIn('id', array_column($list, 'id'))->update(['is_read' => 1]);
        }
        $this->ws->push($frame->fd, json($list, 'success', 'get_msg'));
    }

    public function read($frame)
    {
        Db::name('im_msg')->where('id', $frame->data['msg'])->update(['is_read' => 1]);
    }

    public function get_list($data, $is_init = false)
    {
        list($fd, $me) = $data;
        if (strpos($me, '_')) {
            list($me, $you) = explode('_', $me);
        }
        Db::name('im_msg')->where('__from|__to', '=', $me)->where('add_time', '<', strtotime('- ' . $this->save_time))->delete();

        if (isset($you)) {
            $list = Db::name('im_msg')->whereRaw("(__to='{$you}' AND __from='{$me}') OR (__from='{$you}' AND __to='{$me}')")->order('id DESC')->group('__from,__to')->field('__from,__to')->select();
        } else {
            $list = Db::name('im_msg')->where('__from|__to', '=', $me)->order('id DESC')->group('__from,__to')->field('__from,__to')->select();
        }

        if ($list) {
            $list = array_unique(array_merge(array_column($list, '__from'), array_column($list, '__to')));
            $temp = array_search($me, $list);
            if ($temp !== false) {
                unset($list[$temp]);
            }
            $list    = array_values($list);
            $res     = [];
            $on_line = [];
            $field   = [
                'user'       => ['pk' => 'user_id', 'field' => 'nick_name,user_name,avatar'],
                'seller'     => ['pk' => 'id', 'field' => 'username,avatar'],
                'admin_user' => ['pk' => 'id', 'field' => 'username,admin_avatar']
            ];
            $unread  = Db::name('im_msg')->where(['__to' => $me, 'is_read' => 0])->group('__from')->column('count(id) as count', '__from');

            foreach ($list as $index => $user) {
                $res[$index]['user']      = $user;
                $temp                     = explode('-', $user);
                $res[$index]['user_info'] = Db::name($temp[0])->where($field[$temp[0]]['pk'], $temp[1])->field($field[$temp[0]]['field'])->find();
                //获取好友列表中第一个人的聊天记录
                if ($index == 0) {
                    $msg_list = Db::name('im_msg')->whereRaw("(__to='{$user}' AND __from='{$me}') OR (__from='{$user}' AND __to='{$me}')")->order('id DESC')->select();
                    //设置消息为已读状态
                    if (array_sum(array_column($msg_list, 'is_read')) != count($msg_list)) {
                        Db::name('im_msg')->whereIn('id', array_column($msg_list, 'id'))->update(['is_read' => 1]);
                    }
                    $res[$index]['unread']      = 0;
                    $res[$index]['msg_history'] = $msg_list;
                } else {
                    $res[$index]['msg_history'] = [];
                    $res[$index]['unread']      = $unread[$user] ?? 0;
                }
                $res[$index]['is_online'] = Cache::tag('login')->has($user);

                if ($res[$index]['is_online']) {
                    $on_line[] = Cache::tag('login')->get($user);
                }
            }
        } else {
            $res = [];
        }

        $this->ws->push($fd, json($res, 'success', 'init'));
        //登录时,投放异步任务,对其好友推送上线通知
        if ($is_init && isset($on_line) && count($on_line)) {
            return ['fds' => $on_line, 'online_user' => $me];
        } else {
            return ['fds' => []];
        }
    }

    //fixme 暂时不用
    public function finish($data)
    {
        switch ($data['type']) {
            case 'mysql_update':
                Db::name($data['table'])->where($data['pk'], $data['condition'])->update($data['data']);
                break;
            default:
                $this->log->error('finish::' . var_export($data));
        }
    }
}